using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Design;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Linq;
using EnvDTE;
using Microsoft.VisualStudio.Shell;
using VsPackageCommon;

namespace NotifyPropertyWeaverVsPackage
{
	[Export, PartCreationPolicy(CreationPolicy.Shared)]
	public class MenuConfigure
	{

		OleMenuCommand configureCommand;
		OleMenuCommand disableCommand;
		CurrentProjectFinder currentProjectFinder;
		ExceptionDialog exceptionDialog;
		ConfigureMenuCallback configureMenuCallback;
		DisableMenuConfigure disableMenuConfigure;
		IMenuCommandService menuCommandService;

		[ImportingConstructor]
		public MenuConfigure(CurrentProjectFinder currentProjectFinder, ExceptionDialog exceptionDialog, ConfigureMenuCallback configureMenuCallback, DisableMenuConfigure disableMenuConfigure, IMenuCommandService menuCommandService)
		{
			this.exceptionDialog = exceptionDialog;
			this.configureMenuCallback = configureMenuCallback;
			this.disableMenuConfigure = disableMenuConfigure;
			this.menuCommandService = menuCommandService;
			this.currentProjectFinder = currentProjectFinder;
		}

		public void RegisterMenus()
		{
			var cmdSet = new Guid("af0fbcae-2924-42bf-adb7-31202b59250a");
			var configureCommandId = new CommandID(cmdSet, 1);
			configureCommand = new OleMenuCommand(delegate { configureMenuCallback.ConfigureCallback(); }, configureCommandId);
			configureCommand.BeforeQueryStatus += delegate { CommandStatusCheck(); };
			menuCommandService.AddCommand(configureCommand);

			var disableCommandId = new CommandID(cmdSet, 2);
			disableCommand = new OleMenuCommand(delegate { disableMenuConfigure.DisableCallback(); }, disableCommandId)
			                 	{
			                 		Enabled = false
			                 	};
			disableCommand.BeforeQueryStatus += delegate { CommandStatusCheck(); };
			menuCommandService.AddCommand(disableCommand);
		}

		void CommandStatusCheck()
		{
			try
			{
				disableCommand.Enabled = true;
				configureCommand.Enabled = true;
				var project = currentProjectFinder.GetCurrentProject();
				if (project == null)
				{
					disableCommand.Enabled = false;
					configureCommand.Enabled = false;
					return;
				}
                disableCommand.Enabled = ContainsWeavingTask(project); 
			}
			catch (COMException exception)
			{
				exceptionDialog.HandleException(exception);
			}
			catch (Exception exception)
			{
				exceptionDialog.HandleException(exception);
			}
		}

		static bool ContainsWeavingTask(Project project)
        {
            string fullName;
            try
            {
                fullName = project.FullName;
            }
            catch (NotImplementedException)
            {
                //HACK: can happen during an upgrade from VS 2008
                return false;
            }
		    try
			{
                //HACK: for when VS incorrectly calls configure when no project is avaliable
                if (string.IsNullOrWhiteSpace(fullName))
                {
                    return false;
                }
				var xDocument = XDocument.Load(fullName);
				var target = xDocument.BuildDescendants("Target")
					.Where(x => string.Equals((string)x.Attribute("Name"), "AfterCompile", StringComparison.InvariantCultureIgnoreCase)
					).FirstOrDefault();
				if (target == null)
				{
					return false;
				}
				return target.BuildDescendants("NotifyPropertyWeaverMsBuildTask.WeavingTask").Count() > 0;
			}
			catch (Exception exception)
			{
				throw new Exception(string.Format("Could not check project '{0}' for weaving task", fullName), exception);
			}
		}
	}
}